/*
 * SM_sounder.c
 *
 *  Created on: 2023年8月15日
 *      Author: zlw
 */
#include "device_type.h"
#ifdef SM_OUTSOUND
#include "app_api.h"
#include "app_log.h"
#include "app_cli_cmd.h"
#include "bsp_gpio.h"
#include "app_button.h"
#include "app_led.h"
#include "bsp_iadc.h"
#include "em_emu.h"
#include "softwareMultiTimer.h"
#include "device.h"
#include "bsp_system.h"
#include "net_protocol.h"
#include "app_key_value.h"
#include "bsp_rmu.h"
#include "bsp_wdog.h"
#include "RBFVersion.h"
#include "bsp_timer.h"
#include "app_pwm.h"
#include "git_version.h"
#include "net_aseq.h"
#include "net_packet.h"


#define DEVICE_TX_POWER_DEFAULT  (160)
#define DEVICE_CTUNE_DEFAULT     (125)
#define DEVICE_LFXO_CTUNE_DEFAULT (53)
#define IADC_TIMER_INTERVAL      (4*60)
#define APP_MAJOR_VERSION        (1)
#define APP_MINOR_VERSION        (1)
#define APP_STAGE_VERSION        (2) //max 255
#define SENSOR_VERSION           ((APP_MAJOR_VERSION << 16)|(APP_MINOR_VERSION<<8)|(APP_STAGE_VERSION))

#define UPLINK_FAIL_TIEMS_DISABLE_COMFORT 4
static ds_gpio_t led[3] = {
  {
      .port = gpioPortC,        //右1
      .pin = 5,
      .mode = gpioModePushPull,
      .initial = 0,
      .valid = 1,
  },
  {
      .port = gpioPortC,        //左1
      .pin = 2,
      .mode = gpioModePushPull,
      .initial = 0,
      .valid = 1,
  },
  {
      .port = gpioPortC,        //中
      .pin = 3,
      .mode = gpioModePushPull,
      .initial = 0,
      .valid = 1,
  },

};

#define COMFORTLED_VAR    ((s_option[0] & 0xF0) >> 4)

static MultiTimer s_ComfortLedtimer={.Handle = 0x00AB, .status = EN_MULTITIMER_STATUS_IDLE};
static uint8_t s_comfortLedCtrlIdx = 0;
//static uint8_t isComfortLedOn = 1; 由option替换
static uint8_t s_uplinkFailCnt = 0;

static void setTxpowerDefaule(void);
static void setCtuneDefaule(void);
static void setLfxoCtuneDefaule(void);
static void gpio_state_change_handler(void);
static void SM_button_init(void);
static void SM_sound_battery_enable_start(void);
static void SM_sound_battery_enable_stop(void);
static void SM_beep_enable_gpio_init(void);
static void SM_iadc_init(void);
static void printSoftWareInformation(void);
static void inputStateChangedHandle();
static void comfort_led_start_check();//comfort led 开启检测
static void comfort_led_handle(MultiTimer* timer, void *userData); //comfort led处理
static int netCallback(NET_UP_EVENT_TYPE_EN type, bool isSucced, int8_t rssi, void *pData);

static uint8_t s_option[3] = {0};

/**
 * @brief: 门磁项目相关外设初始化
 * */
void SM_main(void)
{
  setTxpowerDefaule();
  setCtuneDefaule();
  setLfxoCtuneDefaule();
  pwm_init();
  SM_button_init();
  SM_beep_enable_gpio_init();
  startWatchDogTimer();
  printSoftWareInformation();
  reg_net_upload_result(netCallback);//
}

/**
 * @brief: 门磁项目while函数相关处理
 * */
void SM_process(void)
{
  inputStateChangedHandle(); //新增Input/output字段状态更新后的处理
  feedWatchDogHandler();
  SM_key_value_handler();
  gpio_state_change_handler();
  pwm_sound_light_stateMachine_run();
  comfort_led_start_check();
}

static uint8_t get_comfort_led_time(void)
{
  uint8_t led_time[16] = {1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 1};
  return led_time[COMFORTLED_VAR];
}

static void comfort_led_start_check()//comfort led 开启检测
{
  if( COMFORTLED_VAR && 0 == s_comfortLedCtrlIdx
      && getPwmIdleState() && !ledStateGet()//互斥判断，若LED控制权空闲，则开启定时器控制之
      && s_ComfortLedtimer.status == EN_MULTITIMER_STATUS_IDLE
      && s_uplinkFailCnt <= UPLINK_FAIL_TIEMS_DISABLE_COMFORT //无线通信正常时才闪烁
      && isregeist()//仅已注册设备需开启ComfortLed
  )
  {
    softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &s_ComfortLedtimer,(get_comfort_led_time() * 32768) ,comfort_led_handle ,NULL,0);
    s_comfortLedCtrlIdx ++;
  }
}

static void comfort_led_handle(MultiTimer* timer, void *userData)
{
  (void)timer;
  (void)userData;

  uint8_t temp8;
  if( getPwmIdleState() && !ledStateGet() ) //互斥判断，若LED控制权空闲，则开启定时器控制之
  {
    if(s_comfortLedCtrlIdx % 2)//奇数
    {
      softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &s_ComfortLedtimer, (get_comfort_led_time() * 32768) ,comfort_led_handle ,NULL,0);
      // all led off
      ds_gpio_off(&led[0]);
      ds_gpio_off(&led[1]);
      ds_gpio_off(&led[2]);
    }
    else //偶数
    {
      if(COMFORTLED_VAR && s_uplinkFailCnt <= UPLINK_FAIL_TIEMS_DISABLE_COMFORT) //在开led时 判断是否该功能被关闭
      {
        softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &s_ComfortLedtimer,327 ,comfort_led_handle ,NULL,0); //10ms后进入下一态,关闭，仅持续10ms
        temp8 = s_comfortLedCtrlIdx/2;
        if(0 < temp8 && temp8 < 4){
          ds_gpio_on(&led[temp8 - 1]);
        }
      }
      else
      {
        s_comfortLedCtrlIdx = 0;
        return;//表示comfortLed功能被关闭
      }
    }

    s_comfortLedCtrlIdx ++;
    if(s_comfortLedCtrlIdx > 6)
    {
       s_comfortLedCtrlIdx = 1;
    }
  }
  else
  {
    s_comfortLedCtrlIdx = 0; //表明当前comfortLed被打断或关闭，处于idle状态
  }
}

static int netCallback(NET_UP_EVENT_TYPE_EN type, bool isSucced, int8_t rssi, void *pData)
{
  (void)pData;
  (void)type;
  (void)rssi;

  if(isSucced)
  {
      s_uplinkFailCnt = 0;
  }
  else
  {
    if(s_uplinkFailCnt < 250)//
    {
        s_uplinkFailCnt++;
    }
  }
  return 0;
}

/******************get device sleep state***************************/

bool device_sleep_state_get(void)
{
  return getPwmIdleState();
}

/**************** set tx power/ctune defaule***********************/
static void setTxpowerDefaule(void)
{
  int16_t txPowerDeciDbm = 0;
  int ret = getThisParam(RfTxPower, &txPowerDeciDbm);
  if(ret != 0) {
      txPowerDeciDbm = DEVICE_TX_POWER_DEFAULT;
      setThisParam(RfTxPower, &txPowerDeciDbm);
  }
  RAIL_Status_t status = bsp_rf_set_tx_power_bdm(txPowerDeciDbm);
  if (status != RAIL_STATUS_NO_ERROR) {
      DS_app_log_error("set tx power error, status = 0x%x\r\n", status);
  }
}

static void setCtuneDefaule(void)
{
  uint32_t ctune = 0;
  int ret = getThisParam(RfCtune, &ctune);
  if(ret != 0) {
      ctune = DEVICE_CTUNE_DEFAULT;
      setThisParam(RfCtune, &ctune);
  }
  RAIL_Status_t status = bsp_rf_set_ctune(ctune);
  if (status != RAIL_STATUS_NO_ERROR) {
      DS_app_log_error("set ctune error, status = 0x%x\r\n", status);
  }
}

static void setLfxoCtuneDefaule(void)
{
  uint8_t ctune = 0;
  int ret = getThisParam(lfxoCtune, &ctune);
  if(ret != 0) {
      ctune = DEVICE_LFXO_CTUNE_DEFAULT;
      setThisParam(lfxoCtune, &ctune);
  }
  CMU_OscillatorTuningSet(cmuOsc_LFXO,ctune);
}

/************************button handler****************************/

static struct Button btn;
static MultiTimer buttonTimer[3] = {
    {.Handle = 0},
    {.Handle = 1},
    {.Handle = 2},
};

static void ds_btn_state_change_callback(uint8_t intNo, void *ctx);

static ds_button_t button[4] = {
    {
        .port = gpioPortA,
        .pin = 5,
        .mode = gpioModeInput,
        .initial = 0,
        .valid = 0,
        .ds_button_state_change = ds_btn_state_change_callback,
    },
    {
        .port = gpioPortB,
        .pin = 1,
        .mode = gpioModeInput,
        .initial = 0,
        .valid = 0,
        .ds_button_state_change = ds_btn_state_change_callback,
    },
    {
        .port = gpioPortA,
        .pin = 6,
        .mode = gpioModeInput,
        .initial = 0,
        .valid = 1,
        .ds_button_state_change = ds_btn_state_change_callback, //外部电源检测
    },
    {
        .port = gpioPortA,
        .pin = 8,
        .mode = gpioModeInput,
        .initial = 0,
        .valid = 1,
        .ds_button_state_change = ds_btn_state_change_callback, //外置电池检测
    },
};

/**
 * @brief: button timer callback,每10ms轮询一次button状态
 * */
static keyValue_t outputKeyValue = {0x00};

static void inputStateChangedHandle()
{
    if(s_option[1] & 0x1f)
    {
        setDeviceSpvnTime(SPVN_TIME_30S); //
    }
    else if(outputKeyValue.value[0] & (0x01<<7)) //插入外接电源，心跳修改1min
    {
        setDeviceSpvnTime(SPVN_TIME_1MIN);
    }
    else
    {
        setDeviceSpvnTime(SPVN_TIME_5MIN);
    }
}

static void buttonTimerCallback(MultiTimer* timer, void *userData)
{
  (void)userData;

  if(timer->Handle == 0) {
      button_handler(&btn);
  } else if(timer->Handle == 1) {
      if(read_button_level(&button[1]) == button[1].valid) {
          outputKeyValue.value[1] &= ~0x01;
      }
      else {
          outputKeyValue.value[1] |= 0x01;
          pwm_blink_start(SOUND_BLINK_TYPE_OPERATION_TIPS, 1, false, true);
      }
      set_key_value(&outputKeyValue);
      if(false == device_test_sleep_state_get()) {
          DS_app_log_error("temple = 0x%02x \r\n", outputKeyValue.value[1] & 0x01);
      }
  } else if(timer->Handle == 2) {
      if(read_button_level(&button[2]) == button[2].valid) {
          outputKeyValue.value[0] |= (0x01<<7);
          SM_sound_battery_enable_start();
      }
      else {
          outputKeyValue.value[0] &= ~(0x01<<7);
          SM_sound_battery_enable_stop();
      }
      set_key_value(&outputKeyValue);
      if(false == device_test_sleep_state_get()) {
          DS_app_log_error("external power = 0x%02x \r\n", (outputKeyValue.value[0]>>7)&0x01);
      }
  }
}

uint8_t batDetectCnt = 0;
/**
 * @brief:button 1 引脚状态改变时启动button timer
 * */
static void ds_btn_state_change_callback(uint8_t intNo, void *ctx)
{
  (void)intNo;
  ds_button_t *btnDrive = (ds_button_t *)ctx;

  if(btnDrive->port == button[0].port && btnDrive->pin == button[0].pin && buttonTimer[0].status == EN_MULTITIMER_STATUS_IDLE) {
      button_handler(&btn);
  }
  else if(btnDrive->port == button[1].port && btnDrive->pin == button[1].pin && buttonTimer[1].status == EN_MULTITIMER_STATUS_IDLE) {
      softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &buttonTimer[1], 983, buttonTimerCallback,NULL,0);
  }
  else if(btnDrive->port == button[2].port && btnDrive->pin == button[2].pin && buttonTimer[2].status == EN_MULTITIMER_STATUS_IDLE) {
      softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &buttonTimer[2], 983, buttonTimerCallback,NULL,0);
  }
  else if(btnDrive->port == button[3].port && btnDrive->pin == button[3].pin && read_button_level(&button[3]) == button[3].valid) {
      batDetectCnt++;
  }
}

/**
 * @brief: 读取button引脚状态
 * @param： button id
 * @return： gpio 状态
 * */
static uint8_t read_button_GPIO(uint8_t button_id)
{
  // you can share the GPIO read function with multiple Buttons
  switch(button_id)
  {
    case 0:
      return read_button_level(&button[0]);
      break;
    default:
      return 0;
      break;
  }
}

bool isBattVoltageHigh(void)
{
  return true;
}

/**
 * @brief: button 1 按键按下时回调函数
 * @param：btn结构体指针
 * */
static void btn_press_handler(void* butt)
{
  Button* btnHanlde = (Button*)butt;

  DS_app_log_error("btn id = %d event = %d \r\n", btnHanlde->button_id, btnHanlde->event);
  if(btnHanlde->button_id == 0) {
      if(btnHanlde->event == LONG_PRESS_START) {
          startCommissiongJoin(buttonTrigger, other_device);
      }
      else if(btnHanlde->event == SINGLE_CLICK) {
          if(false == device_test_sleep_state_get()) {
              DS_app_log_error("reg btn test \r\n");
          }
      }
  }
}

static void gpio_state_change_handler(void)
{
  if(read_button_level(&button[0]) == button[0].valid) {
      if(buttonTimer[0].status == EN_MULTITIMER_STATUS_IDLE) {
          button_handler(&btn);
      }
  }
  if(read_button_level(&button[1]) != (outputKeyValue.value[1] & 0x01)) {
      if(buttonTimer[1].status == EN_MULTITIMER_STATUS_IDLE) {
          softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &buttonTimer[1], 983, buttonTimerCallback,NULL,0);
      }
  }
  if(read_button_level(&button[2]) != ((outputKeyValue.value[0]>>7)&0x01)) {
      if(buttonTimer[2].status == EN_MULTITIMER_STATUS_IDLE) {
          softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &buttonTimer[2], 983, buttonTimerCallback,NULL,0);
      }
  }
}

/**
 * @brief: button reed初始化；注册不同状态相关回调函数
 * */
static void SM_button_init(void)
{
  ds_button_init(&button[0]);
  ds_button_init(&button[1]);
  ds_button_init(&button[2]);
  ds_button_init(&button[3]);

  getThisParam(ENpbyOption, s_option);

  outputKeyValue.id = 0x10;
  outputKeyValue.valueSize = 2;

  if(read_button_level(&button[2])) {
      outputKeyValue.value[0] |= (0x01<<7);
      SM_sound_battery_enable_start();
  }
  else {
      outputKeyValue.value[0] &= ~(0x01<<7);
      SM_iadc_init();
  }


  if(read_button_level(&button[1]))
    outputKeyValue.value[1] |= (0x01);
  else
    outputKeyValue.value[1] &= ~0x01;

  uint8_t data[5] = {0, 0, 3, 0, 1};
  SM_led_start(data, POWER_ON_BLINK);

  button_init(&btn, &buttonTimer[0], buttonTimerCallback, read_button_GPIO, button[0].valid, 0);
  button_attach(&btn, LONG_PRESS_START, btn_press_handler);
  button_attach(&btn, SINGLE_CLICK, btn_press_handler);
}

/************************led init***************************************/

static MultiTimer ledTimer;
static led_ins_t ledDriver;


/**
 * @brief: led闪烁开始
 * @param： led物模型
 * */
void SM_led_start(uint8_t *data, blinkType_t type)
{
  led_driver_init(&ledDriver, &ledTimer, led[0], led[1], led[2], data, type);
}


/*************************battery enable init***************************************/
static ds_gpio_t batEn = {
      .port = gpioPortC,
      .pin = 6,
      .mode = gpioModePushPull,
      .initial = 0,
      .valid = 1,
};

static MultiTimer batteryTimer = {.Handle = 0};
static uint8_t detectUnPresentTimes = 0;
static uint8_t detectPresentTimes = 0;
static void batteryTimeroutHandlerCallback(MultiTimer* timer, void *userData)
{
  (void)userData;
  if(timer->Handle == 0) {
      if(batDetectCnt >= 5) {
          detectUnPresentTimes ++;
          detectPresentTimes = 0;
          DS_app_log_error("detectUnPresentTimes = %d\r\n", detectUnPresentTimes);
          if(detectUnPresentTimes >= 5) {
              detectUnPresentTimes = 0;
              DS_app_log_error("detectUnPresent\r\n");
              if(((outputKeyValue.value[1] >> 3) & 0x01) == 0) {
                  outputKeyValue.value[1] |= (0x01<<3);
                  set_key_value(&outputKeyValue);
              }
          }
      }
      else {
          detectPresentTimes ++;
          detectUnPresentTimes = 0;
          DS_app_log_error("detectPresentTimes = %d\r\n", detectPresentTimes);
          if(detectPresentTimes >= 5) {
              detectPresentTimes = 0;
              DS_app_log_error("detectPresent\r\n");
              if(((outputKeyValue.value[1] >> 3) & 0x01) == 0x01) {
                  outputKeyValue.value[1] &= ~(0x01<<3);
                  set_key_value(&outputKeyValue);
              }
          }

      }
      DS_app_log_error("batDetectCnt = %d\r\n", batDetectCnt);
      batDetectCnt = 0;
      softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &batteryTimer, 10*32768, batteryTimeroutHandlerCallback,NULL,1);
  }
}

static void SM_sound_battery_enable_start(void)
{
  batDetectCnt = 0;
  detectUnPresentTimes = 0;
  detectPresentTimes = 0;
  SM_iadc_init();
  if(batteryTimer.status == EN_MULTITIMER_STATUS_IDLE) {
      softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &batteryTimer, 10*32768, batteryTimeroutHandlerCallback,NULL,1);
  }
}

static void SM_sound_battery_enable_stop(void)
{
  softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &batteryTimer,0);
}

/************************beep enable gpio init***************************************/

static ds_gpio_t beepEnable = {
    .port = gpioPortD,
    .pin = 3,
    .mode = gpioModePushPull,
    .initial = 0,
    .valid = 1,
};

/**
 * @brief: led闪烁开始
 * @param： led物模型
 * */
static void SM_beep_enable_gpio_init(void)
{
  ds_gpio_init(&beepEnable);
}

void SM_beep_enable(void)
{
  ds_gpio_on(&beepEnable);
}

void SM_beep_disable(void)
{
  ds_gpio_off(&beepEnable);
}

/*****************key value handler*************************/

static MultiTimer optionTimer = {.Handle = 0};

static void optionTimeroutHandlerCallback(MultiTimer* timer, void *userData)
{
  (void)userData;
  (void)timer;
  //ToDo ，调用app_pwm。h中关闭接口
  pwm_soundLight_start(SOUND_LIGHT_OUT_TYPE_OFF,true,true);
}

void recv_option_key_value_handler(uint8_t *option)
{
  if(option[0] != s_option[0] || option[1] != s_option[1] || option[2] != s_option[2]) {
      setThisParam(ENpbyOption, option);
      memcpy(s_option, option, 3);
  }

  if(((option[0]>>2)&0x03) == 0) {
      pwm_sound_volume_set(SOUND_VOLUME_CLASS_MEDIUM);
  }
  else if(((option[0]>>2)&0x03) == 1) {
    pwm_sound_volume_set(SOUND_VOLUME_CLASS_LOW);
  }
  else if(((option[0]>>2)&0x03) == 2) {
      pwm_sound_volume_set(SOUND_VOLUME_CLASS_HIGH);
  }

  if((option[1] & 0x1f) == 0) {
      pwm_soundLight_start(SOUND_LIGHT_OUT_TYPE_OFF, true, true);
  } else if((option[1] & 0x1f) == 1) {
      pwm_soundLight_start(SOUND_LIGHT_OUT_TYPE_INTRUSION_ALARM, false, true);
  } else if((option[1] & 0x1f) == 2) {
      pwm_soundLight_start(SOUND_LIGHT_OUT_TYPE_INTRUSION_ALARM, true, false);
  } else if((option[1] & 0x1f) == 3) {
      pwm_soundLight_start(SOUND_LIGHT_OUT_TYPE_INTRUSION_ALARM, true, true);
  } else if((option[1] & 0x1f) == 4) {
      pwm_soundLight_start(SOUND_LIGHT_OUT_TYPE_FIRE, false, true);
  } else if((option[1] & 0x1f) == 5) {
      pwm_soundLight_start(SOUND_LIGHT_OUT_TYPE_FIRE, true, false);
  } else if((option[1] & 0x1f) == 6) {
      pwm_soundLight_start(SOUND_LIGHT_OUT_TYPE_FIRE, true, true);
  } else if((option[1] & 0x1f) == 7) {
      pwm_soundLight_start(SOUND_LIGHT_OUT_TYPE_SOS, false, true);
  } else if((option[1] & 0x1f) == 8) {
      pwm_soundLight_start(SOUND_LIGHT_OUT_TYPE_SOS, true, false);
  } else if((option[1] & 0x1f) == 9) {
      pwm_soundLight_start(SOUND_LIGHT_OUT_TYPE_SOS, true, true);
  } else if((option[1] & 0x1f) == 10) {
      pwm_soundLight_start(SOUND_LIGHT_OUT_TYPE_MEDICAL, false, true);
  } else if((option[1] & 0x1f) == 11) {
      pwm_soundLight_start(SOUND_LIGHT_OUT_TYPE_MEDICAL, true, false);
  } else if((option[1] & 0x1f) == 12) {
      pwm_soundLight_start(SOUND_LIGHT_OUT_TYPE_MEDICAL, true, true);
  }
  //若开启延时功能使能，则启用该定时器，进行自动关闭动作；
  if((option[1] & 0x1f) != 0) {
      softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &optionTimer, 0);
      softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &optionTimer, (7*60*32768), optionTimeroutHandlerCallback,NULL,1);
  }
}

/************************operation key value handler*************************************/

void recv_operation_key_value_handler(uint8_t *operation)
{
  if((operation[0] & 0x0f) == 0) {
      //pwm_blink_start(SOUND_BLINK_TYPE_OFF, 0, true, true);
  } else if((operation[0] & 0x0f) == 1) {
      pwm_blink_start(SOUND_BLINK_TYPE_OPERATION_TIPS, 1, false, true);
  } else if((operation[0] & 0x0f) == 2) {
      pwm_blink_start(SOUND_BLINK_TYPE_OPERATION_TIPS, 1, true, false);
  } else if((operation[0] & 0x0f) == 3) {
      pwm_blink_start(SOUND_BLINK_TYPE_OPERATION_TIPS, 1, true, true);
  } else if((operation[0] & 0x0f) == 4) {
      pwm_blink_start(SOUND_BLINK_TYPE_OPERATION_TIPS, 2, false, true);
  } else if((operation[0] & 0x0f) == 5) {
      pwm_blink_start(SOUND_BLINK_TYPE_OPERATION_TIPS, 2, true, false);
  } else if((operation[0] & 0x0f) == 6) {
      pwm_blink_start(SOUND_BLINK_TYPE_OPERATION_TIPS, 2, true, true);
  }
}


/*******************battery detect***************************/
static ds_gpio_t batteryGpio = {
      .port = gpioPortD,
      .pin = 2,
      .mode = gpioModePushPull,
      .initial = 1,
      .valid = 1,
};

static ds_gpio_t tempGpio = {
    .port = gpioPortC,
    .pin = 4,
    .mode = gpioModePushPull,
    .initial = 1,
    .valid = 1,
};

static MultiTimer iadcTimer[2] = {
    {.Handle = 0},
    {.Handle = 1},
};

static bool adcState = false;

static void iadcTimerCallback(MultiTimer* timer, void *userData)
{
  (void)userData;

  if(timer->Handle == 0) {
      if(adcState == false) {
          GPIO_PinModeSet(gpioPortA, 0,gpioModeInput,0);
          initIADC(iadcPosInputPortCPin0, iadcPosInputPortAPin7);
          softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &iadcTimer[1], 655, iadcTimerCallback,NULL,0);
      }
      else {
          SM_iadc_init();
      }
  }
  else if(timer->Handle == 1) {
      iadc_scan_stop();
      ds_gpio_off(&batteryGpio);
      GPIO_PinModeSet(gpioPortA, 0,gpioModeDisabled,0);
      GPIO_PinModeSet(gpioPortC, 4, gpioModeDisabled, 0);
      if(get_adc_channel(3)*3 >= 3300 && ((outputKeyValue.value[0] >> 6)&0x01) == 0) {
          outputKeyValue.value[0] |= (0x01<<6);
          set_key_value(&outputKeyValue);
      }
      else if(get_adc_channel(3)*3 < 3300 && ((outputKeyValue.value[0] >> 6)&0x01) == 1){
          outputKeyValue.value[0] &= ~(0x01<<6);
          set_key_value(&outputKeyValue);
      }
      adcState = true;
      if(read_button_level(&button[2]) || get_adc_channel(3)*3 >= 3300) {
          if(get_adc_channel(1) > 114) {    //电池温度小于50度
              ds_gpio_on(&batEn);
          }
          if(read_button_level(&button[2]) ) {
              softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &iadcTimer[0], 120*32768, iadcTimerCallback,NULL,1);
          }
          else {
              softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &iadcTimer[0], IADC_TIMER_INTERVAL*32768, iadcTimerCallback,NULL,1);
          }
      }
      else {
          softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &iadcTimer[0], IADC_TIMER_INTERVAL*32768, iadcTimerCallback,NULL,1);
      }
  }
}

/**
 * @brief: adc init
 * */
static void SM_iadc_init(void)
{
  ds_gpio_init(&batEn);
  ds_gpio_init(&batteryGpio);
  ds_gpio_init(&tempGpio);
  ds_gpio_off(&batEn);

  adcState = false;
  softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &iadcTimer[0], 0);
  softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &iadcTimer[0], 3277, iadcTimerCallback,NULL,0);
}

/**
 * @brief: 获取电压值
 * @return: battery unit:mV
 * */
uint8_t SM_battery_get(void)
{
  uint16_t battery = 4*get_adc_channel(0);
  if(false == device_test_sleep_state_get()) {
      DS_app_log_error("battery = %d \r\n", battery);
  }
  if(battery < 1800 || ((outputKeyValue.value[1] >> 3) & 0x01) == 0x01) {
      battery = 1800;
  }
  else if(battery > 4350) {
      battery = 4350;
  }
  return (battery/10 - 180);
}
/*******************temperature get**************************************/

/**
 * @brief: Get the internal temperature of the chip
 * @return: temperature
 * */
int8_t SM_tempDrv_get(void)
{
  float tempCelsius;
  int8_t result;

  tempCelsius = EMU_TemperatureGet();

  if (tempCelsius < INT8_MIN) {
    tempCelsius = INT8_MIN;
  } else if (tempCelsius > INT8_MAX) {
    tempCelsius = INT8_MAX;
  }

  // adding extra 0.5 before truncating to simulate rounding behavior
  result = (((int8_t) (tempCelsius + 0.5 - INT8_MIN)) + INT8_MIN);

  return result;
}

/**********************get hard information***************************/

/**
 * @brief: get hard information
 * @param: point
 * @return: value length
 * */
uint8_t get_hard_information(uint8_t *data)
{
  hardinfo_t hardInfo = {0x00};
  char psn[16] = "DH0580N00001";
  int ret = 0;

  ret = getThisParam(ENpbyKeyM, hardInfo.psn);
  if(ret != 0) {
      memcpy(hardInfo.psn, psn, sizeof(psn));
      setThisParam(ENpbyKeyM, hardInfo.psn);
  }

  ret = getThisParam(ENbyDeviceType, &hardInfo.deviceType);
  if(ret != 0) {
      hardInfo.deviceType = EN_DEVICE_TYPE_OUT_SOUND;
      setThisParam(ENbyDeviceType, &hardInfo.deviceType);
  }

  ret = getThisParam(ENbyModelType, &hardInfo.modelType);
  if(ret != 0) {
      hardInfo.modelType = 0x01;
      setThisParam(ENbyModelType, &hardInfo.modelType);
  }

  ret = getThisParam(ENbyHardType, &hardInfo.hardType);
  if(ret != 0) {
      hardInfo.hardType = 0x01;
      setThisParam(ENbyHardType, &hardInfo.hardType);
  }

  ret = getThisParam(ENpbyMacID, hardInfo.pmacID);
  if(ret != 0) {
      getMacAddr(hardInfo.pmacID);
      setThisParam(ENpbyMacID, hardInfo.pmacID);
  }

  ret = getThisParam(ENpbyRfVer, hardInfo.pRfVer);
  if(ret != 0
      || hardInfo.pRfVer[0] != MAJOR_VERSION
      || hardInfo.pRfVer[1] != MINOR_VERSION
      || hardInfo.pRfVer[2] != STAGE_VERSION) {
      hardInfo.pRfVer[0] = MAJOR_VERSION;
      hardInfo.pRfVer[1] = MINOR_VERSION;
      hardInfo.pRfVer[2] = STAGE_VERSION;
      setThisParam(ENpbyRfVer, hardInfo.pRfVer);
  }

  ret = getThisParam(ENpbySensorVer, &hardInfo.sensorVer);
  if(ret != 0
      || hardInfo.sensorVer[0] != APP_MAJOR_VERSION
      || hardInfo.sensorVer[1] != APP_MINOR_VERSION
      || hardInfo.sensorVer[2] != APP_STAGE_VERSION) {
      hardInfo.sensorVer[0] = APP_MAJOR_VERSION;
      hardInfo.sensorVer[1] = APP_MINOR_VERSION;
      hardInfo.sensorVer[2] = APP_STAGE_VERSION;
      setThisParam(ENpbySensorVer, &hardInfo.sensorVer);
  }

  memcpy(data, &hardInfo, sizeof(hardInfo));

  return sizeof(hardInfo);
}

/**********************print informatio**************************/
static void printSoftWareInformation(void)
{
  uint8_t macAddr[8] = {0x00};
  getMacAddr(macAddr);
  int16_t txPowerDeciDbm = 0;
  uint32_t ctune = 0;
  char reason[12] = {0};
  uint8_t lfxoTune= 0;
  uint8_t SNNumber[16] = {0x00};

  APP_PRINTF("\r\n*************information***************\r\n");
  uint32_t rst_cause = ds_rmu_init();
  resetToString(rst_cause, reason);
  APP_PRINTF("reset reason   : %s\r\n",reason);
  APP_PRINTF("device mac     : ");
  for(uint8_t i=0;i<7;i++){
      APP_PRINTF("%02x:", macAddr[i]);
  }
  APP_PRINTF("%02x \r\n", macAddr[7]);
  APP_PRINTF("stack version  : v%d.%d.%d \r\n", (STACK_VERSION>>16&0xFF), (STACK_VERSION>>8&0xFF),STACK_VERSION&0xFF);
  APP_PRINTF("app  version   : v%d.%d.%d \r\n", (SENSOR_VERSION>>16&0xFF), (SENSOR_VERSION>>8&0xFF),SENSOR_VERSION&0xFF);
  APP_PRINTF("git  version   : 0x%x\r\n", GIT_VERSION);
  getThisParam(ENpbyKeyM, SNNumber);
  APP_PRINTF("SN number      : %s\r\n", SNNumber);
  APP_PRINTF("device type    : 0x%02X\r\n", EN_DEVICE_TYPE_OUT_SOUND);
  printfDeviceRfFreqInfo();
  getThisParam(RfTxPower, &txPowerDeciDbm);
  APP_PRINTF("device power   : %d \r\n", txPowerDeciDbm);
  getThisParam(RfCtune, &ctune);
  APP_PRINTF("device ctune   : %ld \r\n", ctune);
  getThisParam(lfxoCtune, &lfxoTune);
  APP_PRINTF("device lfxoTune: %d \r\n", lfxoTune);
  APP_PRINTF("build app time : %s %s \r\n", __DATE__, __TIME__);
#ifdef  CONFIG_JENKINS_BUILD_NUMBER
  APP_PRINTF("jenkins build number : %d\r\n", CONFIG_JENKINS_BUILD_NUMBER);
#else
  APP_PRINTF("jenkins build number : 0\r\n");//没定义默认0
#endif
  APP_PRINTF("***************************************\r\n\r\n");
}

/***********************get model api******************************/

static uint8_t device_input_output_state_get(uint8_t *buffer)
{
  buffer[0] = 0x00;
  if(read_button_level(&button[1]) == button[1].valid) {
      buffer[1] &= ~0x01;
  }
  else {
      buffer[1] |= 0x01;
  }

  if(read_button_level(&button[2]) == button[2].valid) {
      buffer[0] |= (0x01<<7);
  }
  else {
      buffer[0] &= ~(0x01<<7);
  }

  if((outputKeyValue.value[0] >> 6) & 0x01) {
      buffer[0] |= (0x01<<6);
  }
  else {
      buffer[0] &= ~(0x01<<6);
  }

  if((outputKeyValue.value[1] >> 3) & 0x01) {
      buffer[1] |= (0x01<<3);
  }
  else {
      buffer[1] &= ~(0x01<<3);
  }

  return 2;
}

uint8_t get_device_state(uint8_t *buffer)
{
  uint8_t data[8] = {0x00};
  uint8_t data_size = 0x00;
  uint8_t index = 0;

  buffer[index] = 0x10;
  index += 1;
  data_size = device_input_output_state_get(data);
  memcpy(&buffer[index], data, data_size);
  memset(data, 0, data_size);
  index += data_size;

  return index;
}

static MultiTimer findMeTimer;

static void findMeTimerCallback(MultiTimer* timer, void *userData)
{
  (void)timer;
  (void)userData;
  uint8_t data[5] = {0};
  SM_led_start(data, NONE_BLINK);
}

void SM_device_QRF_state_Handle(QRFH1_t qrfH1, QRFH2_t qrfH2)
{
  (void)qrfH1;
  uint8_t data[5] = {0};
  if(qrfH2.isFM == 1) {
      data[2] = 15;
      data[3] = 1;
      data[4] = 15;
      SM_led_start(data, FIND_ME_BLINK);
      softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &findMeTimer, 0);
      softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &findMeTimer, 32768*30, findMeTimerCallback,NULL,0);
  }
  else {
      if(findMeTimer.status != EN_MULTITIMER_STATUS_IDLE) {
          softwareMultiTimerStop(EN_LP_HARD_TIMER_EM3_SYS_RTC_1, &findMeTimer,0);
          SM_led_start(data, NONE_BLINK);
      }
  }
}

/**********************set gpio mode default*************************/

void staticPowerGpioInit(void)
{
  CMU_ClockEnable(cmuClock_GPIO, true);
  GPIO_PinModeSet(gpioPortA, 3,gpioModePushPull,1);
  GPIO_PinModeSet(gpioPortA, 4,gpioModeInputPull,0);
  GPIO_PinModeSet(gpioPortA, 7,gpioModeInput,0);
  GPIO_PinModeSet(gpioPortB, 0,gpioModeInputPull,1);
  GPIO_PinModeSet(gpioPortC, 0,gpioModeInput,0);

}
#endif
